home *** CD-ROM | disk | FTP | other *** search
- /* Machine-dependent code which would otherwise be in inflow.c and core.c,
- for GDB, the GNU debugger.
- Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc.
-
- This file is part of GDB.
-
- GDB is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 1, or (at your option)
- any later version.
-
- GDB is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GDB; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- /* This one is a try to use the MiNT PROCFS for debugging. I simply re-hacked
- all calls to ptrace into calls to Fopen/Fclose/Fcntl. I really hope this
- works, but it's a bit messy. At best, *VERY* little error checking is done.
- I should really do this some time...
-
- Suggestions, comments and bugfixes welcome. Send mail to
-
- Joerg.Hessdoerfer@EUROPA.rs.kp.dlr.de (preferred 'till May '93)
- Hessdorf@sun.ph-cip.uni-koeln.de
-
- */
-
- #include <stdio.h>
- #include "defs.h"
- #include "param.h"
- #include "frame.h"
- #include "inferior.h"
-
- #include <sys/param.h>
- #include <sys/dir.h>
- #include <signal.h>
- #include <sys/ioctl.h>
- #include <fcntl.h>
-
- #include <mintbind.h>
- #include <uproc.h> /* uproc.h from mint-distrib. Doesn't need ufile.h */
- #define PCTXTSIZE (('P'<< 8) | 3)
- #define PSETFLAGS (('P'<< 8) | 4)
- #define PGETFLAGS (('P'<< 8) | 5)
- #define PTRACESFLAGS (('P'<< 8) | 6)
- #define PTRACEGFLAGS (('P'<< 8) | 7)
- # define P_ENABLE (1 << 0) /* enable tracing */
-
- #define PTRACEGO (('P'<< 8) | 8)
- #define PTRACEFLOW (('P'<< 8) | 9)
- #define PTRACESTEP (('P'<< 8) | 10)
- #define PTRACE11 (('P'<< 8) | 11) /* unused, reserved */
-
- #define SHMGETBLK (('M'<< 8) | 0)
- #define SHMSETBLK (('M'<< 8) | 1)
-
- #include <st-out.h>
- #include <sys/file.h>
- #include <sys/stat.h>
-
- #include <symtab.h> /* needed for relocator */
-
- extern char registers[];
-
- extern int errno;
- extern int attach_flag;
-
-
- int inferior_handle;
- char inferior_name[64];
-
- /* This function simply calls ptrace with the given arguments.
- It exists so that all calls to ptrace are isolated in this
- machine-dependent file. */
- /* That's what it had done - now it calls Fcntl with the same ideas,
- but only some ptrace modes are supported (well, only the ones used
- from outside in gdb). */
- int
- call_ptrace (request, pid, arg3, arg4)
- int request, pid, arg3, arg4;
- {
- char name[64];
- int handle;
-
- switch(request)
- {
- case 0:
- sprintf(name,"U:\\PROC\\.%03d",Pgetpid());
- handle=Fopen(name,2);
- Fcntl(handle,P_ENABLE,PTRACESFLAGS);
- Fclose(handle);
- break;
-
- default:
- printf("_call_ptrace() called with unimplemented request: %d\n",request);
- }
-
- }
-
- kill_inferior ()
- {
- short msig;
-
- if (remote_debugging)
- return;
- if (inferior_pid == 0)
- return;
-
- msig=SIGKILL; /* signal can't be ignored! */
- Fcntl(inferior_handle,&msig,PTRACEGO); /* set the child in motion... */
- Fclose(inferior_handle);
-
- wait (0);
- inferior_died ();
- }
-
- /* This is used when GDB is exiting. It gives less chance of error.*/
-
- kill_inferior_fast ()
- {
- short msig;
-
- if (remote_debugging)
- return;
- if (inferior_pid == 0)
- return;
-
- msig=SIGKILL; /* signal can't be ignored! */
- Fcntl(inferior_handle,&msig,PTRACEGO); /* set the child in motion... */
- Fclose(inferior_handle);
-
- wait (0);
- }
-
- /* Resume execution of the inferior process.
- If STEP is nonzero, single-step it.
- If SIGNAL is nonzero, give it that signal. */
-
- void
- resume (step, signal)
- int step;
- int signal;
- {
- errno = 0;
- if (remote_debugging)
- remote_resume (step, signal);
- else
- {
- short msig;
- msig=signal;
- errno=Fcntl(inferior_handle,&msig,step ? PTRACESTEP : PTRACEGO);
- if (errno)
- perror_with_name ("ptrace");
- }
- }
-
- #ifdef ATTACH_DETACH
-
- /* Start debugging the process whose number is PID. */
-
- attach (pid)
- int pid;
- {
- errno = 0;
- sprintf(inferior_name,"U:\\PROC\\.%03d",pid);
- inferior_handle=Fopen(inferior_name,2);
- if(inferior_handle>0)errno=Fcntl(inferior_handle,P_ENABLE,PTRACESFLAGS);
- else errno=inferior_handle;
-
- if (errno)
- perror_with_name ("ptrace");
- attach_flag = 1;
- return pid;
- }
-
- /* Stop debugging the process whose number is PID
- and continue it with signal number SIGNAL.
- SIGNAL = 0 means just continue it. */
-
- void
- detach (signal)
- int signal;
- {
- errno = 0;
-
- errno=Fcntl(inferior_handle,0,PTRACESFLAGS);
- Fclose(inferior_handle);
-
- if (errno)
- perror_with_name ("ptrace");
- attach_flag = 0;
- }
- #endif /* ATTACH_DETACH */
-
- void
- fetch_inferior_registers ()
- {
- long curprocaddr;
- long ctxtsize;
- CONTEXT c;
-
- if (remote_debugging)
- remote_fetch_registers (registers);
- else
- {
- Fcntl(inferior_handle,&curprocaddr,PPROCADDR); /* get start of process' base page */
- Fcntl(inferior_handle,&ctxtsize,PCTXTSIZE); /* get length of process' context */
- curprocaddr-=2*ctxtsize; /* get start of process' first context */
- Fseek(curprocaddr,inferior_handle,0); /* advance to this address */
- Fread(inferior_handle,(long)sizeof(CONTEXT),&c); /* and read the context */
-
- bcopy (&c.regs, registers, 16 * 4);
- #ifdef FP0_REGNUM
- bcopy (&c.fregs, ®isters[REGISTER_BYTE (FP0_REGNUM)],3*4*8);
- #endif
- *(int *)®isters[REGISTER_BYTE (PS_REGNUM)] = (int)((unsigned short)c.sr);
- *(int *)®isters[REGISTER_BYTE (PC_REGNUM)] = c.pc;
- #ifdef FP0_REGNUM
- bcopy (&c.fstate, ®isters[REGISTER_BYTE (FPC_REGNUM)],216);
- bcopy (&c.fctrl, ®isters[REGISTER_BYTE (FPC_REGNUM)]+216,3*4);
- #endif
- }
- }
-
- /* Store our register values back into the inferior.
- If REGNO is -1, do this for all registers.
- Otherwise, REGNO specifies which register (so we can save time). */
-
- store_inferior_registers (regno)
- int regno;
- {
- long curprocaddr;
- long ctxtsize;
- CONTEXT c;
-
- if (remote_debugging)
- remote_store_registers (registers);
- else
- {
- bcopy (registers, &c.regs, 16 * 4);
- #ifdef FP0_REGNUM
- bcopy (®isters[REGISTER_BYTE (FP0_REGNUM)], &c.fregs,8*3*4);
- #endif
- c.sr = *(int *)®isters[REGISTER_BYTE (PS_REGNUM)];
- c.pc = *(int *)®isters[REGISTER_BYTE (PC_REGNUM)];
-
- #ifdef FP0_REGNUM
- bcopy (®isters[REGISTER_BYTE (FPC_REGNUM)],&c.fstate,216);
- bcopy (®isters[REGISTER_BYTE (FPC_REGNUM)]+216,&c.fctrl,3*4);
- #endif
-
- Fcntl(inferior_handle,&curprocaddr,PPROCADDR); /* get start of process' base page */
- Fcntl(inferior_handle,&ctxtsize,PCTXTSIZE); /* get length of process' context */
- curprocaddr-=2*ctxtsize; /* get start of process' first context */
- Fseek(curprocaddr,inferior_handle,0); /* advance to this address */
- Fwrite(inferior_handle,(long)sizeof(CONTEXT),&c); /* and write the context */
-
- }
- }
-
-
- /* Copy LEN bytes from inferior's memory starting at MEMADDR
- to debugger memory starting at MYADDR.
- On failure (cannot read from inferior, usually because address is out
- of bounds) returns the value of errno. */
-
- int
- read_inferior_memory (memaddr, myaddr, len)
- CORE_ADDR memaddr;
- char *myaddr;
- int len;
- {
- register int i;
- /* Round starting address down to longword boundary. */
- register CORE_ADDR addr = memaddr & - sizeof (int);
- /* Round ending address up; get number of longwords that makes. */
- register int count
- = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int);
- /* Allocate buffer of that many longwords. */
- register int *buffer = (int *) alloca (count * sizeof (int));
- extern int errno;
-
- if(remote_debugging)
- {
- /* Read all the longwords */
- for (i = 0; i < count; i++, addr += sizeof (int))
- {
- errno = 0;
- buffer[i] = remote_fetch_word (addr);
- if (errno)
- return errno;
- }
-
- /* Copy appropriate bytes out of the buffer. */
- bcopy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len);
- }
- else
- {
- Fseek(memaddr,inferior_handle,0);
- errno=Fread(inferior_handle,len,myaddr);
- if(errno<0){ errno=-(errno); return errno; }
- else errno=0;
- }
- return 0;
- }
-
- /* Copy LEN bytes of data from debugger memory at MYADDR
- to inferior's memory at MEMADDR.
- On failure (cannot write the inferior)
- returns the value of errno. */
-
- int
- write_inferior_memory (memaddr, myaddr, len)
- CORE_ADDR memaddr;
- char *myaddr;
- int len;
- {
- register int i;
- /* Round starting address down to longword boundary. */
- register CORE_ADDR addr = memaddr & - sizeof (int);
- /* Round ending address up; get number of longwords that makes. */
- register int count
- = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int);
- /* Allocate buffer of that many longwords. */
- register int *buffer = (int *) alloca (count * sizeof (int));
- extern int errno;
-
- /* Fill start and end extra bytes of buffer with existing memory data. */
-
- if (remote_debugging)
- {
- buffer[0] = remote_fetch_word (addr);
-
- if (count > 1)
- buffer[count - 1]
- = remote_fetch_word (addr + (count - 1) * sizeof (int));
-
- /* Copy data to be written over corresponding part of buffer */
-
- bcopy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len);
-
- /* Write the entire buffer. */
-
- for (i = 0; i < count; i++, addr += sizeof (int))
- {
- errno = 0;
- remote_store_word (addr, buffer[i]);
- if (errno)
- return errno;
- }
- }
- else
- {
- Fseek(memaddr,inferior_handle,0);
- errno=Fwrite(inferior_handle,len,myaddr);
- if(errno<0){ errno=-(errno); return errno; }
- else errno=0;
- }
- return 0;
- }
-
- long inferior_gettxtstrt(void)
- {
- long curprocaddr;
-
- if(inferior_pid)
- {
- Fcntl(inferior_handle,&curprocaddr,PBASEADDR);
- curprocaddr+=256;
- return curprocaddr;
- }
- else return NULL;
- }
-
-
- /* Machine-dependent code which would otherwise be in core.c */
- /* Work with core dump and executable files, for GDB. */
-
- #ifndef N_TXTADDR
- #define N_TXTADDR(hdr) 0
- #endif /* no N_TXTADDR */
-
- #ifndef N_DATADDR
- #define N_DATADDR(hdr) hdr.a_text
- #endif /* no N_DATADDR */
-
- /* Non-zero if this is an object (.o) file, rather than an executable.
- Distinguishing between the two is rarely necessary (and seems like
- a hack, but there is no other way to get the text and data
- addresses--N_TXTADDR should probably take care of
- this, but it doesn't). */
- /* This definition will not work
- if someone decides to make ld preserve relocation info. */
- #define IS_OBJECT_FILE(hdr) (hdr.a_trsize != 0)
-
- /* Make COFF and non-COFF names for things a little more compatible
- to reduce conditionals later. */
-
- #ifdef COFF_FORMAT
- #define a_magic magic
- #endif
-
- #ifndef COFF_FORMAT
- #ifndef AOUTHDR
- #define AOUTHDR struct aexec
- #endif
- #endif
-
- extern char *sys_siglist[];
-
- /* Hook for `exec_file_command' command to call. */
-
- extern void (*exec_file_display_hook) ();
-
- /* File names of core file and executable file. */
-
- extern char *corefile;
- extern char *execfile;
-
- /* Descriptors on which core file and executable file are open.
- Note that the execchan is closed when an inferior is created
- and reopened if the inferior dies or is killed. */
-
- extern int corechan;
- extern int execchan;
-
- /* Last modification time of executable file.
- Also used in source.c to compare against mtime of a source file. */
-
- extern int exec_mtime;
-
- /* Virtual addresses of bounds of the two areas of memory in the core file. */
-
- extern CORE_ADDR data_start;
- extern CORE_ADDR data_end;
- extern CORE_ADDR stack_start;
- extern CORE_ADDR stack_end;
-
- /* Virtual addresses of bounds of two areas of memory in the exec file.
- Note that the data area in the exec file is used only when there is no core file. */
-
- extern CORE_ADDR text_start;
- extern CORE_ADDR text_end;
-
- extern CORE_ADDR exec_data_start;
- extern CORE_ADDR exec_data_end;
-
- /* Address in executable file of start of text area data. */
-
- extern int text_offset;
-
- /* Address in executable file of start of data area data. */
-
- extern int exec_data_offset;
-
- /* Address in core file of start of data area data. */
-
- extern int data_offset;
-
- /* Address in core file of start of stack area data. */
-
- extern int stack_offset;
-
- #ifdef COFF_FORMAT
- /* various coff data structures */
-
- extern FILHDR file_hdr;
- extern SCNHDR text_hdr;
- extern SCNHDR data_hdr;
-
- #endif /* not COFF_FORMAT */
-
- /* a.out header saved in core file. */
-
- extern AOUTHDR core_aouthdr;
-
- /* a.out header of exec file. */
-
- extern AOUTHDR exec_aouthdr;
-
- extern void validate_files ();
-
- core_file_command (filename, from_tty) /* on a ST, we don't have cor dumps - so don't use that */
- char *filename;
- int from_tty;
- {
- }
-
- exec_file_command (filename, from_tty)
- char *filename;
- int from_tty;
- {
- int val;
-
- /* Eliminate all traces of old exec file.
- Mark text segment as empty. */
-
- if (execfile)
- free (execfile);
- execfile = 0;
- data_start = 0;
- data_end -= exec_data_start;
- text_start = 0;
- text_end = 0;
- exec_data_start = 0;
- exec_data_end = 0;
- if (execchan >= 0)
- close (execchan);
- execchan = -1;
-
- /* Now open and digest the file the user requested, if any. */
-
- if (filename)
- {
- filename = tilde_expand (filename);
- make_cleanup (free, filename);
-
- execchan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0,
- &execfile);
- if (execchan < 0)
- perror_with_name (filename);
- {
- struct stat st_exec;
- val = myread (execchan, &exec_aouthdr, sizeof (AOUTHDR));
-
- if (val < 0)
- perror_with_name (filename);
-
- text_start = A_TXTOFF (exec_aouthdr);
- exec_data_start = A_DATOFF (exec_aouthdr);
-
- text_offset = A_TXTOFF (exec_aouthdr);
- exec_data_offset = A_TXTOFF (exec_aouthdr) + exec_aouthdr.a_text;
-
- text_end = text_start + exec_aouthdr.a_text;
- exec_data_end = exec_data_start + exec_aouthdr.a_data;
- data_start = exec_data_start;
- data_end += exec_data_start;
- }
- validate_files ();
- }
- else if (from_tty)
- printf ("No exec file now.\n");
-
- /* Tell display code (if any) about the changed file name. */
- if (exec_file_display_hook)
- (*exec_file_display_hook) (filename);
- }
-
-
- /*** JOE: this was taken from JRD's port of GDB 2.6!
- Thanx, pal! That *REALLY* helped! ***/
-
- /********************************************************************
-
- This next thing is the symbol-table relocator. We use it after
- starting a child program.
-
- Walk thru all symbol tables looking for syms in VAR_NAMESPACE.
- When find one, if its address_class is LOC_STATIC, relocate its
- value by base_address. Then cross fingers and pray...
-
- */
- relocate_apropriate_symbols(base_address)
- long base_address;
- {
- struct symtab * s;
- struct symbol * sym;
- struct blockvector * bv, *last_bv = 0;
- struct block * block;
- struct linetable * l;
- int nsyms, symnum, i;
- extern char *version;
-
- #ifdef DEBUG
- if(atari_debug)
- {
- fprintf_filtered(stderr,"Reloc constant %ld %X\n", base_address, base_address);
- }
- #endif
- for (s = symtab_list ; s ; s = s->next)
- {
- l = LINETABLE(s);
- #ifdef DEBUG
- if(atari_debug)
- {
- fprintf_filtered(stderr,
- "reloc syms table %X file '%s' linetable %08X(%ld) %d items\n",
- s, s->filename, l,l, l->nitems);
- }
- #endif
- {
- int n = l->nitems;
- struct linetable_entry *item;
-
- #ifdef DEBUG
- if(atari_debug && (n <= 0))
- {
- fprintf_filtered(stderr,"*********linetable with %d items\n", n);
- }
- #endif
- for (i = 0 ; i < n ; i++)
- {
- item = &(l->item[i]);
- #ifdef DEBUG
- if(atari_debug)
- {
- fprintf_filtered(stderr, " %d: line %d %X(%ld)->%X(%ld)\n",
- i, item->line, item->pc, item->pc,
- item->pc+base_address, item->pc+base_address);
- }
- #endif
- item->pc += base_address;
- }
- }
- bv = BLOCKVECTOR (s);
- if (bv == last_bv)
- {
- /* already relocated */
- #ifdef DEBUG
- if(atari_debug)
- {
- fprintf_filtered(stderr,"Skipping block vector %X(%d) already relocated\n", bv,bv);
- }
- #endif
- continue;
- }
- last_bv = bv;
- for (i = 0 ; i < BLOCKVECTOR_NBLOCKS(bv) ; i++)
- {
- block = BLOCKVECTOR_BLOCK (bv, i);
- #ifdef DEBUG
- if(atari_debug)
- {
- fprintf_filtered(stderr, " block %d: in %X(%d)\n", i, bv, bv);
- }
- #endif
- relocate_apropriate_block_symbols(block, base_address);
- }
- }
- #ifdef DEBUG
- if(atari_debug)
- {
- fprintf_filtered(stderr,"Relocatings %d misc functions\n", misc_function_count);
- }
- #endif
- /* relocate the misc functions */
- for (i = 0; i < misc_function_count; i++)
- {
- #ifdef DEBUG
- if(atari_debug > 1)
- {
- fprintf_filtered(stderr, "%s: %X(%ld)->%X(%ld)\n", misc_function_vector[i].name,
- misc_function_vector[i].address, misc_function_vector[i].address,
- misc_function_vector[i].address+base_address, misc_function_vector[i].address+base_address);
- }
- #endif
- misc_function_vector[i].address += base_address;
- }
-
- }
-
- relocate_apropriate_block_symbols(block, base_address)
- struct block * block;
- long base_address;
- {
- struct symbol * sym;
- int nsyms, symnum;
-
- /* for ( ; block ; block = BLOCK_SUPERBLOCK(block)) */
- {
- BLOCK_START(block) += base_address;
- BLOCK_END(block) += base_address;
- nsyms = BLOCK_NSYMS (block);
- #ifdef DEBUG
- if(atari_debug)
- {
- fprintf_filtered(stderr, " %d syms block %X(%ld)\n", nsyms, block, block);
- }
- #endif
- for (symnum = 0 ; symnum < nsyms ; symnum++)
- {
- sym = BLOCK_SYM (block, symnum);
- #ifdef DEBUG
- if(atari_debug)
- {
- fprintf_filtered(stderr, " sym %d %X name '%s'",
- symnum, sym, SYMBOL_NAME(sym));
- }
- #endif
- if ((sym->namespace == VAR_NAMESPACE) &&
- ((sym->class == LOC_STATIC) || (sym->class == LOC_LABEL)))
- {
- #ifdef DEBUG
- if(atari_debug)
- {
- fprintf_filtered(stderr, " is relocatable: (%s, %s) %X->%X %ld->%ld\n",
- d_namespace[sym->namespace], d_aclass[sym->class],
- sym->value.value, sym->value.value + base_address,
- sym->value.value, sym->value.value + base_address);
- }
- #endif
- sym->value.value += base_address;
- }
- else if (sym->class == LOC_BLOCK)
- {
- #ifdef DEBUG
- if(atari_debug)
- {
- fprintf_filtered(stderr, " is a LOC_block(%s %s)... %X\n",
- d_namespace[sym->namespace], d_aclass[sym->class], sym->value.block);
- }
- #endif
- #if 0
- relocate_apropriate_block_symbols(sym->value.block, base_address);
- #else
- {
- struct block * bl = sym->value.block;
- #ifdef DEBUG0
- if(atari_debug)
- {
- fprintf_filtered(stderr, " start %X->%X\n",
- BLOCK_START(bl), BLOCK_START(bl) + base_address);
- }
- #endif
- /* BLOCK_START(bl) += base_address; */
- #ifdef DEBUG0
- if(atari_debug)
- {
- fprintf_filtered(stderr, " end %X->%X\n",
- BLOCK_END(bl), BLOCK_END(bl) + base_address);
- }
- #endif
- /* BLOCK_END(bl) += base_address; */
- }
- #endif
- #ifdef DEBUG
- if(atari_debug)
- {
- fprintf_filtered(stderr, " ...end block\n");
- }
- #endif
- }
- else
- {
- #ifdef DEBUG
- if(atari_debug)
- {
- fprintf_filtered(stderr, " is not relocatable: (%s, %s)\n",
- d_namespace[sym->namespace], d_aclass[sym->class]);
- }
- #endif
- }
- }
- }
- }
-
- /* This one's by JOE. It relocates breakpoints at 'run_command' time,
- so it's possible to specify breakpoints *BEFORE* actually running
- the inferior. Thus no stop immediate after the start of the
- inferior is needed. Nice, huh?!? - We come close to the behaviour
- of the UN*X GDB!! */
-
- static char break_insn[] = BREAKPOINT;
-
- enum enable { disabled, enabled, temporary, delete};
-
- struct breakpoint
- {
- struct breakpoint *next;
- /* Number assigned to distinguish breakpoints. */
- int number;
- /* Address to break at. */
- CORE_ADDR address;
- /* Line number of this address. Redundant. */
- int line_number;
- /* Symtab of file of this address. Redundant. */
- struct symtab *symtab;
- /* Zero means disabled; remember the info but don't break here. */
- enum enable enable;
- /* Non-zero means a silent breakpoint (don't print frame info
- if we stop here). */
- unsigned char silent;
- /* Number of stops at this breakpoint that should
- be continued automatically before really stopping. */
- int ignore_count;
- /* "Real" contents of byte where breakpoint has been inserted.
- Valid only when breakpoints are in the program. */
- char shadow_contents[sizeof break_insn];
- /* Nonzero if this breakpoint is now inserted. */
- char inserted;
- /* Nonzero if this is not the first breakpoint in the list
- for the given address. */
- char duplicate;
- /* Chain of command lines to execute when this breakpoint is hit. */
- struct command_line *commands;
- /* Stack depth (address of frame). If nonzero, break only if fp
- equals this. */
- FRAME_ADDR frame;
- /* Conditional. Break only if this expression's value is nonzero. */
- struct expression *cond;
- };
-
- #define ALL_BREAKPOINTS(b) for (b = breakpoint_chain; b; b = b->next)
-
- /* Chain of all breakpoints defined. */
-
- extern struct breakpoint *breakpoint_chain;
-
- void relocate_breakpoints(long address)
- {
- struct breakpoint *b;
-
- ALL_BREAKPOINTS(b) b->address+=address;
- }
-
-